package com.opennews.openplatform.service;

import com.opennews.openplatform.entity.tables.records.RoleRecord;
import com.opennews.openplatform.jooq.DSLContextWrapper;
import com.opennews.openplatform.jooq.RecordHelper;
import com.opennews.openplatform.myspringbootcore.common.constant.RoleType;
import lombok.RequiredArgsConstructor;
import org.jooq.DSLContext;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.opennews.openplatform.entity.Tables.ROLE;

@RequiredArgsConstructor
@Service
public class RoleService {
    private final DSLContext dslContext;
    private final DSLContextWrapper dslContextWrapper;

    /**
     * Prepares the initial data for Role.
     */
    public void init() {
        if (dslContextWrapper.count(ROLE) == 0) {
            List<RoleRecord> records = new ArrayList<>();
            records.add(createRecord(RoleType.ROLE_SYSTEM_ADMIN, "系统管理员", "当前整个系统的管理员，不属于任何账户。"));
            records.add(createRecord(RoleType.ROLE_ACCOUNT_GROUP_ADMIN, "账户管理员", "可对当前账户组下的各项，如银行卡片和收支类别等进行管理。"));
            records.add(createRecord(RoleType.ROLE_ACCOUNT_GROUP_USER, "用户", "账户组普通用户"));
            records.add(createRecord(RoleType.ROLE_ACCOUNT_GROUP_VIEWER, "查看者", "账户组只读用户，仅可查看，不可操作数据。"));
            dslContext.batchInsert(records);
        }
    }

    /**
     * Queries the role id by authority.
     *
     * @param authority: The string of the authority. AKA role name.
     * @return
     */
    public String queryId(String authority) {
        return dslContext.selectFrom(ROLE)
                .where(ROLE.AUTHORITY.eq(authority))
                .fetchOne(ROLE.ID);
    }

    /**
     * Queries non system level roles with id and title.
     *
     * @return The list of map instance which contains keys below.
     * id: String of role id.
     * authority: String of role authority. AKA role name.
     * title: String of role title.
     * description: String of role description.
     */
    public List<Map<String, Object>> queryNonSystemLevelRoles() {
        // All system level roles which will be ignored from this result.
        List<String> systemRoles = List.of(
                RoleType.ROLE_SYSTEM_ADMIN
        );

        return dslContext.select(
                        ROLE.ID.as("id"),
                        ROLE.AUTHORITY.as("authority"),
                        ROLE.TITLE.as("title"),
                        ROLE.DESCRIPTION.as("description")
                )
                .from(ROLE)
                .where(ROLE.AUTHORITY.notIn(systemRoles))
                .fetchMaps();
    }

    /**
     * Queries all roles with id and title.
     *
     * @return The list of map instance which contains keys below.
     * id: String of role id.
     * title: String of role title.
     */
    public List<Map<String, Object>> queryAllRoles() {
        return dslContext.select(
                        ROLE.ID.as("id"),
                        ROLE.TITLE.as("title")
                )
                .from(ROLE)
                .fetchMaps();
    }

    /**
     * Counts by role id list and role authority.
     *
     * @param ids:       String list of role ids.
     * @param authority: String of role authority.
     * @return Number of match.
     */
    public int countByRoleIdsAndAuthority(List<String> ids, String authority) {
        return dslContextWrapper.count(ROLE, ROLE.ID.in(ids)
                .and(ROLE.AUTHORITY.eq(authority)));
    }

    private RoleRecord createRecord(String authority, String title, String description) {
        RoleRecord record = dslContext.newRecord(ROLE);
        RecordHelper.setCommonFields(record);
        record.setAuthority(authority);
        record.setTitle(title);
        record.setDescription(description);

        return record;
    }
}
